/*
 * Copyright 2002-2017 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.beans.factory;

import org.springframework.beans.BeansException;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;

/**
 * 作为访问Spring Bean容器的跟接口定义,他是访问Bean容器的最底层客户端视图实现.
 * 像{@link ListableBeanFactory}和{@link org.springframework.beans.factory.config.ConfigurableBeanFactory}
 * 这种有独特目的性的类也是它的实现之一.
 * <p>
 * 这个接口的实现本身会持有海量的bean定义,这些bean根据用户对他们的定义会拥有一个一个独一无二的字符串名称.
 * 而该工厂基于这些定义能够返回一个包含对象的原型实例或者单例实例,具体是哪种实例,取决于我们在使用spring时的配置.
 * 当然,如果我们有特殊的目的,根据我们所应用的环境,可以进行我们个性化的配置.
 * 不过需要注意的是,这里的单例只是在工厂范围内是单例的.
 * <p>
 * The root interface for accessing a Spring bean container.
 * <p>
 * 作为访问Spring Bean容器的跟接口.
 * <p>
 * This is the basic client view of a bean container;
 * <p>
 * 他是访问bean容器的基本客户端视图.
 * <p>
 * further interfaces such as {@link ListableBeanFactory} and
 * {@link org.springframework.beans.factory.config.ConfigurableBeanFactory}
 * are available for specific purposes.
 * <p>
 * 像{@link ListableBeanFactory}和{@link org.springframework.beans.factory.config.ConfigurableBeanFactory}
 * 都是它的实现类,它们用在一些特殊的场景下.
 * <p>
 * <p>This interface is implemented by objects that hold a number of bean definitions,
 * each uniquely identified by a String name. Depending on the bean definition,
 * the factory will return either an independent instance of a contained object
 * (the Prototype design pattern), or a single shared instance (a superior
 * alternative to the Singleton design pattern, in which the instance is a
 * singleton in the scope of the factory). Which type of instance will be returned
 * depends on the bean factory configuration: the API is the same. Since Spring
 * 2.0, further scopes are available depending on the concrete application
 * context (e.g. "request" and "session" scopes in a web environment).
 * <p>
 * <p>
 * 在Spring里,BeanFactory是应用程序组件的中央注册表,他集中了应用程序组件的配置,这样做的最大的好处就是,
 * 我们不需要针对单个对象再去读取属性文件,毕竟IO操作的资源占用还是很大的.
 * <p>
 * 不过,需要注意的是,常规的DI/IOC(依赖注入)使用setter方法注入或者函数注入来配置这些"Bean"对象,spring认为这种方式是放置('push'),即从
 * 外部往里面放,而BeanFactory维护所有Bean,然后再根据依赖查找出来,被认为是拿(pull)的方式,当然这里放置和拿的目标,个人认为应该就是BeanFactory
 * 本身了.
 * <p>
 * <p>
 * <p>The point of this approach is that the BeanFactory is a central registry
 * of application components, and centralizes configuration of application
 * components (no more do individual objects need to read properties files,
 * for example). See chapters 4 and 11 of "Expert One-on-One J2EE Design and
 * Development" for a discussion of the benefits of this approach.
 * <p>
 * <p>Note that it is generally better to rely on Dependency Injection
 * ("push" configuration) to configure application objects through setters
 * or constructors, rather than use any form of "pull" configuration like a
 * BeanFactory lookup. Spring's Dependency Injection functionality is
 * implemented using this BeanFactory interface and its subinterfaces.
 * <p>
 * <p>
 * 通常来说,Bean工厂会通过加载配置文件来加载这些Bean的定义,就比如以前的Spring*.XMl配置文件,
 * 读取XML文件里面的Bean定义,然后通过{@code org.springframework.beans}里面的一些类和方法配置管理Bean.
 * 不过,我们也可以直接在java代码里根据需要直接创建java对象.
 * 所以这些Bean定义到底是使用LDAP还是PDBMS又或者干脆是XML文件或者Properties文件并不重要,但是spring还是推荐最好使用DI的方式来定义Bean.
 * <p>
 * <p>Normally a BeanFactory will load bean definitions stored in a configuration
 * source (such as an XML document), and use the {@code org.springframework.beans}
 * package to configure the beans. However, an implementation could simply return
 * Java objects it creates as necessary directly in Java code. There are no
 * constraints on how the definitions could be stored: LDAP, RDBMS, XML,
 * properties file, etc. Implementations are encouraged to support references
 * amongst beans (Dependency Injection).
 * <p>
 * {@link ListableBeanFactory}和{@link HierarchicalBeanFactory}都是本类的实现,但是两者相比较,{@link HierarchicalBeanFactory}中
 * 所有的操作都会检查它的父级工厂.
 * 也就说,如果在{@link HierarchicalBeanFactory}中找不到一个Bean的实例,那么就去它的直接父工厂中去查找,而且在
 * {@link HierarchicalBeanFactory}中,父工厂中同名的bean实例会被覆盖.
 * <p>
 * 当然说了那么多,其实{@link BeanFactory}的作用主要就是获取Bean以及Bean里的各种属性.
 * <p>
 * <p>
 * <p>In contrast to the methods in {@link ListableBeanFactory}, all of the
 * operations in this interface will also check parent factories if this is a
 * {@link HierarchicalBeanFactory}. If a bean is not found in this factory instance,
 * the immediate parent factory will be asked. Beans in this factory instance
 * are supposed to override beans of the same name in any parent factory.
 * <p>
 * <p>Bean factory implementations should support the standard bean lifecycle interfaces
 * as far as possible. The full set of initialization methods and their standard order is:
 * <ol>
 * <li>BeanNameAware's {@code setBeanName}
 * <li>BeanClassLoaderAware's {@code setBeanClassLoader}
 * <li>BeanFactoryAware's {@code setBeanFactory}
 * <li>EnvironmentAware's {@code setEnvironment}
 * <li>EmbeddedValueResolverAware's {@code setEmbeddedValueResolver}
 * <li>ResourceLoaderAware's {@code setResourceLoader}
 * (only applicable when running in an application context)
 * <li>ApplicationEventPublisherAware's {@code setApplicationEventPublisher}
 * (only applicable when running in an application context)
 * <li>MessageSourceAware's {@code setMessageSource}
 * (only applicable when running in an application context)
 * <li>ApplicationContextAware's {@code setApplicationContext}
 * (only applicable when running in an application context)
 * <li>ServletContextAware's {@code setServletContext}
 * (only applicable when running in a web application context)
 * <li>{@code postProcessBeforeInitialization} methods of BeanPostProcessors
 * <li>InitializingBean's {@code afterPropertiesSet}
 * <li>a custom init-method definition
 * <li>{@code postProcessAfterInitialization} methods of BeanPostProcessors
 * </ol>
 * <p>
 * <p>On shutdown of a bean factory, the following lifecycle methods apply:
 * <ol>
 * <li>{@code postProcessBeforeDestruction} methods of DestructionAwareBeanPostProcessors
 * <li>DisposableBean's {@code destroy}
 * <li>a custom destroy-method definition
 * </ol>
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @author Chris Beams
 * @see BeanNameAware#setBeanName
 * @see BeanClassLoaderAware#setBeanClassLoader
 * @see BeanFactoryAware#setBeanFactory
 * @see org.springframework.context.ResourceLoaderAware#setResourceLoader
 * @see org.springframework.context.ApplicationEventPublisherAware#setApplicationEventPublisher
 * @see org.springframework.context.MessageSourceAware#setMessageSource
 * @see org.springframework.context.ApplicationContextAware#setApplicationContext
 * @see org.springframework.web.context.ServletContextAware#setServletContext
 * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization
 * @see InitializingBean#afterPropertiesSet
 * @see org.springframework.beans.factory.support.RootBeanDefinition#getInitMethodName
 * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization
 * @see DisposableBean#destroy
 * @see org.springframework.beans.factory.support.RootBeanDefinition#getDestroyMethodName
 * @since 13 April 2001
 */
public interface BeanFactory {

	/**
	 * 用于取消引用工厂bean实例,将他和由他创建的bean区分开.
	 * 举例来说,如果有一个叫做myJndiObject的工厂bean,当我们通过&myJndiObject获取该实例的时候,会返回myJndiObject工厂本身,
	 * 而不会返回他对应的,生产出的bean实例.
	 * <p>
	 * Used to dereference a {@link FactoryBean} instance and distinguish it from
	 * beans <i>created</i> by the FactoryBean. For example, if the bean named
	 * {@code myJndiObject} is a FactoryBean, getting {@code &myJndiObject}
	 * will return the factory, not the instance returned by the factory.
	 */
	String FACTORY_BEAN_PREFIX = "&";


	/**
	 * 获取一个共享或者独立的bean实例,这个方法里面的实现,使得BeanFactory能够成为原型模式以及单例模式的替代品
	 * (BeanFactory控制了bean的生命周期),对于单例bean,调用者可以保留对返回对象的引用.
	 * 同时该方法获取bean时,会将别名转化为对应的beanName,如果在当前工厂实例中没有找到该bean,还会迭代询问父工厂.
	 * <p>
	 * Return an instance, which may be shared or independent, of the specified bean.
	 * <p>This method allows a Spring BeanFactory to be used as a replacement for the
	 * Singleton or Prototype design pattern. Callers may retain references to
	 * returned objects in the case of Singleton beans.
	 * <p>Translates aliases back to the corresponding canonical bean name.
	 * Will ask the parent factory if the bean cannot be found in this factory instance.
	 *
	 * @param name the name of the bean to retrieve
	 * @return an instance of the bean
	 * @throws NoSuchBeanDefinitionException if there is no bean definition
	 *                                       with the specified name
	 * @throws BeansException                if the bean could not be obtained
	 */
	Object getBean(String name) throws BeansException;

	/**
	 * 功能类似与{@link #getBean(String)},但是增加了校验返回Bean类型的操作,其目的是为了当获取到的Bean实例类型不对时,
	 * 抛出一个BeanNotOfRequiredTypeException异常,而不是ClassCastException.
	 * <p>
	 * Return an instance, which may be shared or independent, of the specified bean.
	 * <p>Behaves the same as {@link #getBean(String)}, but provides a measure of type
	 * safety by throwing a BeanNotOfRequiredTypeException if the bean is not of the
	 * required type. This means that ClassCastException can't be thrown on casting
	 * the result correctly, as can happen with {@link #getBean(String)}.
	 * <p>Translates aliases back to the corresponding canonical bean name.
	 * Will ask the parent factory if the bean cannot be found in this factory instance.
	 *
	 * @param name         the name of the bean to retrieve
	 * @param requiredType type the bean must match. Can be an interface or superclass
	 *                     of the actual class, or {@code null} for any match. For example, if the value
	 *                     is {@code Object.class}, this method will succeed whatever the class of the
	 *                     returned instance.
	 * @return an instance of the bean
	 * @throws NoSuchBeanDefinitionException  if there is no such bean definition
	 * @throws BeanNotOfRequiredTypeException if the bean is not of the required type
	 * @throws BeansException                 if the bean could not be created
	 */
	<T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException;

	/**
	 * 方法{@link #getBean(String)}的扩展,增加了指定构造参数/工厂方法参数的能力.
	 * 这些给出的参数会覆盖bean定义中指定的缺省参数.
	 * <p>
	 * Return an instance, which may be shared or independent, of the specified bean.
	 * <p>Allows for specifying explicit constructor arguments / factory method arguments,
	 * overriding the specified default arguments (if any) in the bean definition.
	 *
	 * @param name the name of the bean to retrieve
	 * @param args arguments to use when creating a bean instance using explicit arguments
	 *             (only applied when creating a new instance as opposed to retrieving an existing one)
	 * @return an instance of the bean
	 * @throws NoSuchBeanDefinitionException if there is no such bean definition
	 * @throws BeanDefinitionStoreException  if arguments have been given but
	 *                                       the affected bean isn't a prototype
	 * @throws BeansException                if the bean could not be created
	 * @since 2.5
	 */
	Object getBean(String name, Object... args) throws BeansException;

	/**
	 * 功能类似于{@link #getBean(String)},同样都是获取Bean实例的方式,不过该方法是通过Bean实例类型的Class来获取的.
	 * <p>
	 * Return the bean instance that uniquely matches the given object type, if any.
	 * <p>This method goes into {@link ListableBeanFactory} by-type lookup territory
	 * but may also be translated into a conventional by-name lookup based on the name
	 * of the given type. For more extensive retrieval operations across sets of beans,
	 * use {@link ListableBeanFactory} and/or {@link BeanFactoryUtils}.
	 *
	 * @param requiredType type the bean must match; can be an interface or superclass.
	 *                     {@code null} is disallowed.
	 * @return an instance of the single bean matching the required type
	 * @throws NoSuchBeanDefinitionException   if no bean of the given type was found
	 * @throws NoUniqueBeanDefinitionException if more than one bean of the given type was found
	 * @throws BeansException                  if the bean could not be created
	 * @see ListableBeanFactory
	 * @since 3.0
	 */
	<T> T getBean(Class<T> requiredType) throws BeansException;

	/**
	 * 方法{@link #getBean(String, Object...)}的变形,通过指定的Class类型获取对应的实例,同时通过指定
	 * 的参数来覆盖掉实例原有的构造参数/工厂方法参数.
	 * <p>
	 * Return an instance, which may be shared or independent, of the specified bean.
	 * <p>Allows for specifying explicit constructor arguments / factory method arguments,
	 * overriding the specified default arguments (if any) in the bean definition.
	 * <p>This method goes into {@link ListableBeanFactory} by-type lookup territory
	 * but may also be translated into a conventional by-name lookup based on the name
	 * of the given type. For more extensive retrieval operations across sets of beans,
	 * use {@link ListableBeanFactory} and/or {@link BeanFactoryUtils}.
	 *
	 * @param requiredType type the bean must match; can be an interface or superclass.
	 *                     {@code null} is disallowed.
	 * @param args         arguments to use when creating a bean instance using explicit arguments
	 *                     (only applied when creating a new instance as opposed to retrieving an existing one)
	 * @return an instance of the bean
	 * @throws NoSuchBeanDefinitionException if there is no such bean definition
	 * @throws BeanDefinitionStoreException  if arguments have been given but
	 *                                       the affected bean isn't a prototype
	 * @throws BeansException                if the bean could not be created
	 * @since 4.1
	 */
	<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;


	/**
	 * 该方法的作用是判断在工厂中是否获取到给定名称的bean定义或者单例对象,如果在当前工厂中没有找到对应的实例且该工厂还是一个嵌套工厂,
	 * 那么就会去迭代询问其祖先辈工厂来查找
	 * 如果找到了,那就返回true,但是需要注意的是,这里返回true只是表明了工厂中有这个bean定义,但是这个bean定义是具体的还是抽象的,亦或是即时加载
	 * 还是懒加载的都无所谓,所以,即使该方法返回了true,那也不一定就能够通过getBean方法返回实例.
	 * <p>
	 * Does this bean factory contain a bean definition or externally registered singleton
	 * instance with the given name?
	 * <p>If the given name is an alias, it will be translated back to the corresponding
	 * canonical bean name.
	 * <p>If this factory is hierarchical, will ask any parent factory if the bean cannot
	 * be found in this factory instance.
	 * <p>If a bean definition or singleton instance matching the given name is found,
	 * this method will return {@code true} whether the named bean definition is concrete
	 * or abstract, lazy or eager, in scope or not. Therefore, note that a {@code true}
	 * return value from this method does not necessarily indicate that {@link #getBean}
	 * will be able to obtain an instance for the same name.
	 *
	 * @param name the name of the bean to query
	 * @return whether a bean with the given name is present
	 */
	boolean containsBean(String name);

	/**
	 * 判断指定名称对应的bean定义是不是一个可共享的单例实例,即,通过getBean方法获取该实例是总是会返回同一个实例.
	 * 需要注意的是,及时该方法返回了false,也并不意味着他一定不是单例,他可能在其他的作用域内是一个单例实例,这时候,我们可以通过isPrototype()
	 * 方法来明确的判断他到底是不是独立的实体.
	 * 当然,该方法也会对传入的bean名称做别名转换,以及迭代询问父工厂等操作.
	 * <p>
	 * Is this bean a shared singleton? That is, will {@link #getBean} always
	 * return the same instance?
	 * <p>Note: This method returning {@code false} does not clearly indicate
	 * independent instances. It indicates non-singleton instances, which may correspond
	 * to a scoped bean as well. Use the {@link #isPrototype} operation to explicitly
	 * check for independent instances.
	 * <p>Translates aliases back to the corresponding canonical bean name.
	 * Will ask the parent factory if the bean cannot be found in this factory instance.
	 *
	 * @param name the name of the bean to query
	 * @return whether this bean corresponds to a singleton instance
	 * @throws NoSuchBeanDefinitionException if there is no bean with the given name
	 * @see #getBean
	 * @see #isPrototype
	 */
	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

	/**
	 * 判断指定名称的bean是不是一个原型实例,也就说每次调用getBean方法都会返回一个独立的实体.
	 * 和isSingleton()类似,它的方法在返回false时,其结果也是略有些含糊的,返回false的时候,可能表名他不是一个独立的实体,但是
	 * 在其他的作用域范围内,他就可能是了,所以这时候,我们就需要调用isSingleton来确定他是不是单例类了.
	 * 所以这里isSingleton和isPrototype可以互补.
	 * 当然,该方法同样也会对传入的bean名称做别名转换,以及迭代询问父工厂等操作.
	 * <p>
	 * Is this bean a prototype? That is, will {@link #getBean} always return
	 * independent instances?
	 * <p>Note: This method returning {@code false} does not clearly indicate
	 * a singleton object. It indicates non-independent instances, which may correspond
	 * to a scoped bean as well. Use the {@link #isSingleton} operation to explicitly
	 * check for a shared singleton instance.
	 * <p>Translates aliases back to the corresponding canonical bean name.
	 * Will ask the parent factory if the bean cannot be found in this factory instance.
	 *
	 * @param name the name of the bean to query
	 * @return whether this bean will always deliver independent instances
	 * @throws NoSuchBeanDefinitionException if there is no bean with the given name
	 * @see #getBean
	 * @see #isSingleton
	 * @since 2.0.3
	 */
	boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

	/**
	 * 检查通过指定名称获取的bean实例是否是指定类型,具体的说就是检查通过getBean方法获取的指定名称的Bean实例是否是指定类型的对象.
	 * 当然,该方法同样也会对传入的bean名称做别名转换,以及迭代询问父工厂等操作.
	 * <p>
	 * Check whether the bean with the given name matches the specified type.
	 * More specifically, check whether a {@link #getBean} call for the given name
	 * would return an object that is assignable to the specified target type.
	 * <p>Translates aliases back to the corresponding canonical bean name.
	 * Will ask the parent factory if the bean cannot be found in this factory instance.
	 *
	 * @param name        the name of the bean to query
	 * @param typeToMatch the type to match against (as a {@code ResolvableType})
	 * @return {@code true} if the bean type matches,
	 * {@code false} if it doesn't match or cannot be determined yet
	 * @throws NoSuchBeanDefinitionException if there is no bean with the given name
	 * @see #getBean
	 * @see #getType
	 * @since 4.2
	 */
	boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;

	/**
	 * 同{@link #isTypeMatch(String, ResolvableType)}.
	 * <p>
	 * Check whether the bean with the given name matches the specified type.
	 * More specifically, check whether a {@link #getBean} call for the given name
	 * would return an object that is assignable to the specified target type.
	 * <p>Translates aliases back to the corresponding canonical bean name.
	 * Will ask the parent factory if the bean cannot be found in this factory instance.
	 *
	 * @param name        the name of the bean to query
	 * @param typeToMatch the type to match against (as a {@code Class})
	 * @return {@code true} if the bean type matches,
	 * {@code false} if it doesn't match or cannot be determined yet
	 * @throws NoSuchBeanDefinitionException if there is no bean with the given name
	 * @see #getBean
	 * @see #getType
	 * @since 2.0.1
	 */
	boolean isTypeMatch(String name, @Nullable Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

	/**
	 * 获取指定名称的bean的类型,具体来说是当通过指定名称调用getBean获取到的对象的类型.
	 * 对于一个工厂Bean来说,返回的该工厂Bean创建的对象的类型.通过共产bean的getObjectType()方法来获取.
	 * 当然,该方法同样也会对传入的bean名称做别名转换,以及迭代询问父工厂等操作.
	 * <p>
	 * Determine the type of the bean with the given name. More specifically,
	 * determine the type of object that {@link #getBean} would return for the given name.
	 * <p>For a {@link FactoryBean}, return the type of object that the FactoryBean creates,
	 * as exposed by {@link FactoryBean#getObjectType()}.
	 * <p>Translates aliases back to the corresponding canonical bean name.
	 * Will ask the parent factory if the bean cannot be found in this factory instance.
	 *
	 * @param name the name of the bean to query
	 * @return the type of the bean, or {@code null} if not determinable
	 * @throws NoSuchBeanDefinitionException if there is no bean with the given name
	 * @see #getBean
	 * @see #isTypeMatch
	 * @since 1.1.2
	 */
	@Nullable
	Class<?> getType(String name) throws NoSuchBeanDefinitionException;

	/**
	 * 获取指定名称对应的bean的所有别名,如果传入的名称本身也是一个别名,那么返回的就是bean名称和别名的集合,在集合里,第一个参数就是Bean的名称.
	 * 当然,该方法同样也会对传入的bean名称做别名转换,以及迭代询问父工厂等操作.
	 * <p>
	 * Return the aliases for the given bean name, if any.
	 * All of those aliases point to the same bean when used in a {@link #getBean} call.
	 * <p>If the given name is an alias, the corresponding original bean name
	 * and other aliases (if any) will be returned, with the original bean name
	 * being the first element in the array.
	 * <p>Will ask the parent factory if the bean cannot be found in this factory instance.
	 *
	 * @param name the bean name to check for aliases
	 * @return the aliases, or an empty array if none
	 * @see #getBean
	 */
	String[] getAliases(String name);

}
